using System;
using System.Collections.Generic;
using System.Text;
using CodePlex.Resourceful.Wadl;
using System.Xml;
using System.IO;
using CodePlex.Resourceful.Bookmarks.Model;

namespace CodePlex.Resourceful.Bookmarks.Controllers
{
    public class BookmarksController : BaseController
    {


        public BookmarksController(BookmarkEngine engine)
            : base(engine)
        {

        }


        // pg 191-192
        private void RenderBookmarks(IRepresentationContext context, string mediaType, UserAccount user, IEnumerable<Bookmark> bookmarks)
        {
            // figure out a current value for the last-modified header
            Bookmark mostRecentBookmark = Utils.Max(bookmarks, delegate(Bookmark lhs, Bookmark rhs)
            {
                return lhs.Timestamp.CompareTo(rhs.Timestamp);
            });

            // conditional get
            if (mostRecentBookmark != null)
            {
                context.Response.SetHeader(HttpHeader.LastModified, Utils.ToHttpDate(mostRecentBookmark.Timestamp));

                if (context.Request.IfModifiedSince.HasValue
                    && mostRecentBookmark.Timestamp <= context.Request.IfModifiedSince.Value)
                {
                    context.Response.Render(HttpStatus.NotModified);
                    return;

                }
            }


            // render as xml
            if (mediaType == MediaType.ApplicationXml)
            {
                string response = Utils.ToString(delegate(XmlTextWriter xwriter)
                {
                    using (Utils.StartElement(xwriter, "bookmarks"))
                    {
                        foreach (Bookmark bookmark in bookmarks)
                        {
                            bookmark.ToXml(xwriter);
                        }
                    }

                });

                context.Response.Render(HttpStatus.OK, MediaType.ApplicationXml, response);
            }
            // render as atom
            else if (mediaType == MediaType.ApplicationAtomXml)
            {
                string response = Utils.ToString(delegate(XmlTextWriter xwriter)
                  {
                      using (Utils.StartElement(xwriter, "feed"))
                      {
                          xwriter.WriteAttributeString("xmlns", "http://www.w3.org/2005/Atom");

                          xwriter.WriteElementString("title", "Bookmarks for " + user.Name);
                          xwriter.WriteElementString("screen", "");
                          xwriter.WriteElementString("updated", Utils.ToAtomDate(mostRecentBookmark == null ? DateTime.Now : mostRecentBookmark.Timestamp));

                          using (Utils.StartElement(xwriter, "link"))
                          {
                              xwriter.WriteAttributeString("href", BookmarksUrl(context, user.Name) + ".atom");
                              xwriter.WriteAttributeString("rel", "self");
                          }

                          using (Utils.StartElement(xwriter, "author"))
                          {
                              xwriter.WriteElementString("name", user.Name);
                              xwriter.WriteElementString("uri", UserUrl(context, user.Name));
                              xwriter.WriteElementString("name", user.Email);
                          }
                          foreach (Bookmark bookmark in bookmarks)
                          {

                              using (Utils.StartElement(xwriter, "entry"))
                              {
                                  xwriter.WriteElementString("title", bookmark.ShortDescription);
                                  xwriter.WriteElementString("content", bookmark.LongDescription);
                                  // TODO category
                                  using (Utils.StartElement(xwriter, "link"))
                                  {
                                      xwriter.WriteAttributeString("href", bookmark.URI);
                                      xwriter.WriteAttributeString("rel", "alternate");
                                  }
                                  using (Utils.StartElement(xwriter, "link"))
                                  {
                                      xwriter.WriteAttributeString("href", BookmarkUrl(context, user.Name, bookmark) + ".atom");
                                      xwriter.WriteAttributeString("rel", "self");
                                      xwriter.WriteAttributeString("type", MediaType.ApplicationAtomXml);
                                  }
                                  // TODO recent link
                                  xwriter.WriteElementString("updated", Utils.ToAtomDate(bookmark.Timestamp));
                              }
                          }
                      }

                  });

                context.Response.Render(HttpStatus.OK, MediaType.ApplicationAtomXml, response);

            }
            else
            {
                context.Response.Render(HttpStatus.UnsupportedMediaType);
            }




        }















        // *** "bookmark controller" methods ***


        // pg 199-200
        public void CreateBookmark(IRepresentationContext context)
        {
            string username = context.TemplateParameters["username"];


            UserAccount user = this.Engine.FindUser(username);

            if (user == null)
            {
                this.RenderStatus(context, HttpStatus.NotFound);
                return;
            }

            if (!this.IsAuthorized(context, user))
            {
                return;
            }

            if (context.Request.MediaType != MediaType.ApplicationXml)
            {
                this.RenderStatus(context, HttpStatus.UnsupportedMediaType);
                return;

            }


            Bookmark newBookmark = Bookmark.FromXml(new StreamReader(context.Request.GetEntityStream()));


            Bookmark oldBookmark = this.Engine.FindBookmark(username, newBookmark.URIHash);

            if (oldBookmark != null)
            {
                context.Response.SetHeader(HttpHeader.Location, BookmarkUrl(context, username, oldBookmark));
                context.Response.Render(HttpStatus.Conflict);
                return;
            }

            // create


            this.Engine.Add(newBookmark);

            context.Response.SetHeader(HttpHeader.Location, BookmarkUrl(context, username, newBookmark));
            context.Response.Render(HttpStatus.Created);




        }




        // pg 201
        public void DeleteBookmark(IRepresentationContext context)
        {
            string username = context.TemplateParameters["username"];
            string uriHash = context.TemplateParameters["uri-hash"];

            UserAccount user = this.Engine.FindUser(username);

            if (user == null)
            {
                this.RenderStatus(context, HttpStatus.NotFound);
                return;
            }

            if (!this.IsAuthorized(context, user))
            {
                return;
            }


            Bookmark bookmark = this.Engine.FindBookmark(username, uriHash);

            if (bookmark == null)
            {
                this.RenderStatus(context, HttpStatus.NotFound);
                return;
            }


            // delete

            this.Engine.Remove(bookmark);

            this.RenderStatus(context, HttpStatus.OK);



        }


        // pg 200
        public void UpdateBookmark(IRepresentationContext context)
        {
            string username = context.TemplateParameters["username"];
            string uriHash = context.TemplateParameters["uri-hash"];

            UserAccount user = this.Engine.FindUser(username);

            if (user == null)
            {
                this.RenderStatus(context, HttpStatus.NotFound);
                return;
            }

            if (!this.IsAuthorized(context, user))
            {
                return;
            }


            Bookmark oldBookmark = this.Engine.FindBookmark(username, uriHash);

            if (oldBookmark == null)
            {
                this.RenderStatus(context, HttpStatus.NotFound);
                return;
            }

            Bookmark newBookmark = Bookmark.FromXml(new StreamReader(context.Request.GetEntityStream()));


            // update

            bool changingUri = (newBookmark.URIHash != uriHash);
            if (changingUri && this.Engine.FindBookmark(username, newBookmark.URIHash) != null)
            {
                this.RenderStatus(context, HttpStatus.Conflict);
                return;
            }

            this.Engine.Remove(oldBookmark);
            this.Engine.Add(newBookmark);

            if (changingUri)
            {
                context.Response.SetHeader(HttpHeader.Location, this.BookmarkUrl(context, username, newBookmark));
                this.RenderStatus(context, HttpStatus.MovedPermanently);
            }
            else
            {
                this.RenderStatus(context, HttpStatus.OK);
            }



        }



        // pg 201,191
        public void GetBookmark(IRepresentationContext context)
        {
            string username = context.TemplateParameters["username"];
            string uriHash = context.TemplateParameters["uri-hash"];


            UserAccount user = this.Engine.FindUser(username);

            if (user == null)
            {
                this.RenderStatus(context, HttpStatus.NotFound);
                return;
            }


            Bookmark bookmark = this.Engine.FindBookmark(username, uriHash);

            if (bookmark == null)
            {
                this.RenderStatus(context, HttpStatus.NotFound);
                return;
            }

            this.RenderBookmarks(context, MediaType.ApplicationXml, user, Utils.ToEnumerable(bookmark));
        }




        // pg 199,190
        public void GetBookmarks(IRepresentationContext context)
        {
            this.GetBookmarks(context, MediaType.ApplicationXml);
        }

        public void GetBookmarksAtom(IRepresentationContext context)
        {
            this.GetBookmarks(context, MediaType.ApplicationAtomXml);
        }

        public void GetBookmarks(IRepresentationContext context, string mediaType)
        {
            string username = context.TemplateParameters["username"];

            UserAccount user = this.Engine.FindUser(username);

            if (user == null)
            {
                this.RenderStatus(context, HttpStatus.NotFound);
                return;
            }


            IEnumerable<Bookmark> bookmarks = this.Engine.FindBookmarks(user);

            this.RenderBookmarks(context, mediaType, user, bookmarks);
        }
       


    }
}
